﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using BicycleTrafficSimulator.DataModel;

namespace BicycleTrafficSimulator.DataModel
{
    class CollisionController
    {
        public struct signCoordinatesStruct
        {
            public Vector3 position;
            public float rotation;
            public string type;
            public int orientation;
        }

        City city;
        public enum CollisionType { None, Building, Boundary, Sign, Intersection, BeforeIntersection }


        //bounding boxes needed for city
        private BoundingBox[] buildingBoundingBoxes, intersectionBoundingBoxes, signBoundingBoxes, treeBoundingBoxes;
        private BoundingBox completeCityBox;
        private signCoordinatesStruct[] signCoordinates = new signCoordinatesStruct[3];
        private Vector3[] treePositions;
        private SignDetectingController signDetectingController;

        public BoundingBox[] IntersectionBoundingBoxes
        {
            get { return intersectionBoundingBoxes; }
            set { intersectionBoundingBoxes = value; }
        }

        public BoundingBox[] BuildingBoundingBoxes
        {
            get { return buildingBoundingBoxes; }
            set { buildingBoundingBoxes = value; }
        }

        public BoundingBox CompleteCityBox
        {
            get { return completeCityBox; }
            set { completeCityBox = value; }
        }
        public BoundingBox[] SignBoundingBoxes
        {
            get { return signBoundingBoxes; }
            set { signBoundingBoxes = value; }
        }

        public signCoordinatesStruct[] SignCoordinates
        {
            get { return signCoordinates; }
            set { signCoordinates = value; }
        }

        public BoundingBox[] TreeBoundingBoxes
        {
            get { return treeBoundingBoxes; }
            set { treeBoundingBoxes = value; }
        }

        public Vector3[] TreePositions
        {
            get { return treePositions; }
            set { treePositions = value; }
        }

        private Vector3 rightSignOffset = new Vector3(0.0f, 0.0f, 0.4f);
        private Vector3 leftSignOffset = new Vector3(0.0f, 0.0f, -0.4f);
        private Vector3 frontSignOffset = new Vector3(-0.4f, 0.0f, 0.0f);
        private Vector3 backSignOffset = new Vector3(0.4f, 0.0f, 0.0f);
        private Vector3 treePositionOffset = new Vector3(1.0f, 0.0f, 0.0f);
        private float rightSignRotation = 155.0f;
        private float leftSignRotation = 95.0f;
        private float frontSignRotation = 185.0f;
        private float backSignRotation = 0.0f;

        public CollisionController(City cityParam)
        {
            city = cityParam;
            SetUpBoundingBoxes();
            
        }

        public void SetUpBoundingBoxes()
        {

            List<BoundingBox> bbList = new List<BoundingBox>();
            List<BoundingBox> intersList = new List<BoundingBox>();
            List<BoundingBox> signList = new List<BoundingBox>();
            List<BoundingBox> treeList = new List<BoundingBox>();
            List<Vector3> treePositionList = new List<Vector3>();
            List<signCoordinatesStruct> signCoordinatesList = new List<signCoordinatesStruct>();
            signCoordinatesStruct signCoordinatesElement = new signCoordinatesStruct();
            Vector3 treePosition;

            for (int x = 0; x < city.CityWidth; x++)
            {
                for (int z = 0; z < city.CityLength; z++)
                {
                    int currentType = city.CityPlan[x][z];
                    if (currentType == 10) //if building
                    {
                        Vector3[] objectPoints = new Vector3[2];
                        objectPoints[0] = new Vector3(x - 1.0f, 0, -z + 1.0f);
                        objectPoints[1] = new Vector3(x + 2.0f, 1, -z - 2.0f);
                        BoundingBox objectBox = BoundingBox.CreateFromPoints(objectPoints);
                        bbList.Add(objectBox);
                    }
                    else if ((currentType > 19)
                        && (currentType < 24))
                    {
                        Vector3[] signPoints = new Vector3[2];
                        signPoints[0] = new Vector3(x, 0, -z);
                        signPoints[1] = new Vector3(x + 1, city.BuildingHeights[1], -z - 1);
                        BoundingBox signBox;
                        signCoordinatesElement.position = signPoints[0] + (signPoints[1] - signPoints[0]) / 2;

                        switch (currentType)
                        {
                            case 20:
                                signCoordinatesElement.rotation = rightSignRotation;
                                signCoordinatesElement.position += rightSignOffset;
                                signCoordinatesElement.orientation = 3;
                                signCoordinatesList.Add(signCoordinatesElement);
                                signBox = BoundingBox.CreateFromPoints(new Vector3[2] { signPoints[0] + new Vector3(1.5f, 0.0f, 1.0f), signPoints[1] + new Vector3(-1.0f, 0.0f, 0.0f) });
                                signList.Add(signBox);
                                break;
                            case 21:
                                signCoordinatesElement.rotation = leftSignRotation;
                                signCoordinatesElement.position += leftSignOffset;
                                signCoordinatesElement.orientation = 1;
                                signCoordinatesList.Add(signCoordinatesElement);
                                signBox = BoundingBox.CreateFromPoints(new Vector3[2] { signPoints[0] + new Vector3(-1.0f, 0.0f, -2f), signPoints[1] + new Vector3(0.0f, 0.0f, 1.0f) });
                                signList.Add(signBox);
                                break;
                            case 22:
                                signCoordinatesElement.rotation = frontSignRotation;
                                signCoordinatesElement.position += frontSignOffset;
                                signCoordinatesElement.orientation = 0;
                                signCoordinatesList.Add(signCoordinatesElement);
                                signBox = BoundingBox.CreateFromPoints(new Vector3[2] { signPoints[0] + new Vector3(-1.0f, 0.0f, 0.5f), signPoints[1] + new Vector3(0.0f, 0.0f, 0.5f) });
                                signList.Add(signBox);
                                break;
                            case 23:
                                signCoordinatesElement.rotation = backSignRotation;
                                signCoordinatesElement.position += backSignOffset;
                                signCoordinatesElement.orientation = 2;
                                signCoordinatesList.Add(signCoordinatesElement);
                                signBox = BoundingBox.CreateFromPoints(new Vector3[2] { signPoints[0] + new Vector3(2.0f, 0.0f, -1.5f), signPoints[1] + new Vector3(-1.0f, 0.0f, 0.5f) });
                                signList.Add(signBox);
                                break;
                                ;
                        }


                    }
                    else if ((currentType == 24) || (currentType == 25))
                    {
                        Vector3[] treePoints = new Vector3[2];
                        treePoints[0] = new Vector3(x, 0, -z);
                        treePoints[1] = new Vector3(x + 1, city.SidewalkHeight, -z - 1);
                        BoundingBox treeBox = BoundingBox.CreateFromPoints(treePoints);
                        treeList.Add(treeBox);

                        treePosition = treeBox.Min + (treeBox.Max - treeBox.Min) / 2;

                        switch (currentType)
                        {
                            case 24:
                                treePositionList.Add(treePosition);
                                break;
                            case 25:
                                treePosition += treePositionOffset;
                                treePositionList.Add(treePosition);
                                break;

                        }

                    }
                }
            }

            Vector3[] boundaryPoints = new Vector3[2];
            boundaryPoints[0] = new Vector3(0, 0, 0);
            boundaryPoints[1] = new Vector3(city.CityWidth, 20, -city.CityLength);
            completeCityBox = BoundingBox.CreateFromPoints(boundaryPoints);

            buildingBoundingBoxes = bbList.ToArray();
            intersectionBoundingBoxes = intersList.ToArray();
            signBoundingBoxes = signList.ToArray();
            signCoordinates = signCoordinatesList.ToArray();
            treeBoundingBoxes = treeList.ToArray();
            treePositions = treePositionList.ToArray();
        }

        public string CheckCollision(BoundingSphere sphere)
        {
            for (int i = 0; i < BuildingBoundingBoxes.Length; i++)
                if (BuildingBoundingBoxes[i].Intersects(sphere))
                    return "Building";

            for (int i = 0; i < SignBoundingBoxes.Length; i++)
                if (SignBoundingBoxes[i].Intersects(sphere))
                {
                    return signCoordinates[i].type;
                }
            return "None";
        }

    }
}
